//+----------------------------------------------------------------------
//| ADM Software [ 我宁可 为做过的事而后悔，也不想 因为没尝试而后悔。 ]
//+----------------------------------------------------------------------
//| Copyright (c) 2014 扬州安蝶梦电子商务有限公司 All rights reserved.
//+----------------------------------------------------------------------
//| Author: 曹梦龙 <138888611@qq.com> <http://www.andiemeng.com>
//+----------------------------------------------------------------------
package com.gr100.biz.kit.bmap;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.DbPro;
import com.jfinal.plugin.activerecord.Record;

public class GeoUtils {
    public DbPro ecDb = Db.use("ec");
    public DbPro erpDb = Db.use("erp");
    //求最大值
    public  double getMax(double value1,double value2){
        if(value1>value2){
            return value1;
        }else{
            return value2;
        }
    }
    //求最小值
    public  double getMin(double value1,double value2){

        if(value1<value2){
            return value1;
        }else{
            return value2;
        }
    }

    //判断是否相同
    public  Boolean IsEqual(double value1,double value2){
        double precision = 2e-10; //浮点类型计算时候与0比较时候的容差
        if(value1-value2 < precision && value2-value1 < precision){
            return true;
        }else{
            return false;
        }
    }

    /*
     * 判断点与线段的关系
     * @param {Point} point 点对象
     * @param {Point1} 线段开始point 点对象
     * @param {Point2} 线段结束point 点对象
     * @returns 相交返回1 不想交返回0 射线起点在线段上返回-1
     * @author: 曹梦龙
     */
    public  int isIntersectant(Point Point,Point Point1,Point Point2){


        double X=Point.lng;
        double Y=Point.lat;
        double X1=Point1.lng;
        double Y1=Point1.lat;
        double X2=Point2.lng;
        double Y2=Point2.lat;

        //计算线段的最小和最大值
        double MinX= this.getMin(X1,X2);
        double MaxX= this.getMax(X1,X2);
        double MinY= this.getMin(Y1,Y2);
        double MaxY= this.getMax(Y1,Y2);

        //射线与边无交点的简单判断
        if(Y<MinY || Y>MaxY || X<  MinX){return 0;}

        //判断是否是水平线线段，并且点是否在线段上，
        if(this.IsEqual(MinY, MaxY)){ // 判断是否是水平线段
            if(X>=MinX && X<=MaxX){ //判断点是否在水平线段中
                return -1;
            }  else {
                return 0;
            }
        }

        //获取交点的X坐标
        double X0=X1+(Y-Y1)*(X2-X1)/(Y2-Y1);

        //交点在射线起点 右侧（射线与线段不想交）
        if(X0>X){return 0;}

        //交点与射线起点相同，点在线段上，返回-1；
        if(this.IsEqual(X0, X)){return -1;}

        //如果射线穿过线段下端点则不计数
        if(this.IsEqual(Y, MinY)){return 0;}

        return 1;
    }


    /**
     * 判断点是否多边形内
     * @param {Point} point 点对象
     * @param {PointArray} polygon 多边形对象
     * @returns  点在多边形内返回1,否则返回0,点在多边形线上返回2
     * @author: 曹梦龙
     */
    public  int isPointInPolygon(Point Point,ArrayList<Point> PointArray) {
        //找出多边形的地理坐标的矩形区域
        Bounds bounds = new Bounds(PointArray);
        //首先判断点是否在多边形的外包矩形内，如果在，则进一步判断，否则返回false
        Boolean result=  bounds.isPointInRect(Point);

        if(result==false){
            return 0;

        }

        //计算该点向左方向的水平射线与多边形各边的交点个数
        int nCount=0;
        int nVPonits=PointArray.size();

        for(int i=0;i<nVPonits-1;i++){
            int nFlag=  this.isIntersectant(Point, PointArray.get(i),PointArray.get(i+1));
            if(nFlag<0){return 2;}
            nCount=nCount+nFlag;

        }

        //考虑多边形末顶点和首顶点相连的边
        int nFlag=  this.isIntersectant(Point, PointArray.get(nVPonits-1), PointArray.get(0));
        if(nFlag<0){return 2;}
        nCount=nCount+nFlag;

        return (nCount & 1); //判断奇偶，用的是二进制判断低位是否为1，如果是偶返回0 ，奇数返回1
    }


    /**
     * 判断点在哪个区域内，返回MAP
     * @param {appkey} 应用 APPKEY
     * @param {projectId}  需要参与识别的项目 ID
     * @param {lng} 经度坐标
     * @param {lat} 纬度坐标
     * @returns  返回
     * @author: 曹梦龙
     */
    public Map isPointInArea(String appkey,int projectId,double lng, double lat) {
        Map map = new HashMap();
        map.put("code",0);
        //第一步获取应用 ID
        String sql="select id from gr_lbs_application where appkey=?";
        List<Record> AppList = erpDb.find(sql, appkey);
        if(AppList.size()<1){
            return map;
        }
        int aid=Integer.parseInt(AppList.get(0).getLong("id").toString());
        System.out.println(aid);



        //创建点
        Point point =new Point(lng,lat);
        //多边形数据读取
        sql="select * from gr_lbs_project_area where status=1 and aid=? and pid=?";
        List<Record> PointsDataList = erpDb.find(sql,aid,projectId);
        for(int i=0;i<PointsDataList.size();i++){

            String str=PointsDataList.get(i).getStr("points");
            String pointdataarray[]= str.split(";");
            ArrayList<Point> pointArray = new ArrayList<Point>();
            for(int b=0;b<pointdataarray.length;b++){
                String pointdata[]= pointdataarray[b].split(",");
                Point pointzhi =new Point(Double.parseDouble(pointdata[0]),Double.parseDouble(pointdata[1]));
                pointArray.add(pointzhi);
            }

            int result=  this.isPointInPolygon(point, pointArray);
            if(result>0){

                //System.out.println(PointsDataList.get(i).getStr("areaName"));
                map.put("code",1);
                map.put("id",PointsDataList.get(i).getInt("id"));
                int areainfoid =PointsDataList.get(i).getInt("areainfoid");
                map.put("areainfoid",areainfoid);
                sql="select otherid from gr_lbs_project_areainfo where id=?";
                List<Record> AreainfoList = erpDb.find(sql, areainfoid);
                int areainfootherid=0;
                if(AreainfoList.size()<1){
                    areainfootherid=-999;
                }
                areainfootherid=AreainfoList.get(0).getInt("otherid");
                map.put("areainfootherid",areainfootherid);
                map.put("areaname",PointsDataList.get(i).getStr("areaname"));
                map.put("name",PointsDataList.get(i).getStr("name"));
                map.put("phone",PointsDataList.get(i).getInt("phone"));
                return map;
            }
        }
        return map;
    }


}
